package com.opengl.camera;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import android.opengl.GLES20;
import android.opengl.Matrix;

/*
 * Helper class to make things less messy when
 * setting up our float buffers for the vertex
 * and texture coordinate arrays.
 */
class ByteBufferHelper
{
	static FloatBuffer makeFloatBuffer(float[] arr) {
		ByteBuffer bb;
		bb = ByteBuffer.allocateDirect(arr.length*4);
		bb.order(ByteOrder.nativeOrder());
		FloatBuffer fb = bb.asFloatBuffer();
		fb.put(arr);
		fb.position(0);
		return fb;
	}
}

/*
 * This class draws a triangle.  It doesn't
 * get any simpler than this!
 */
class Triangle {

	private final String vertexShaderCode =
			// This matrix member variable provides a hook to manipulate
			// the coordinates of the objects that use this vertex shader
			"uniform mat4 uMVPMatrix;" +

	        "attribute vec4 vPosition;" +
	        "void main() {" +
	        // the matrix must be included as a modifier of gl_Position
	        "  gl_Position = vPosition * uMVPMatrix;" +
	        "}";

	private final String fragmentShaderCode =
			"precision mediump float;" +
			"uniform vec4 vColor;" +
			"void main() {" +
			"  gl_FragColor = vColor;" +
			"}";

	private final FloatBuffer vertexBuffer;
	private final int mProgram;
	private int m_positionHandle;
	private int m_colorHandle;
	private int m_mvpMatrixHandle;

	// number of coordinates per vertex in this array
	static final int COORDS_PER_VERTEX = 3;
	static float triangleCoords[] = { // in counterclockwise order:
		 0.0f,  0.622008459f, 0.0f,   // top
		-0.5f, -0.311004243f, 0.0f,   // bottom left
		 0.5f, -0.311004243f, 0.0f    // bottom right
	};
	private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
	private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

	// Set color with red, green, blue and alpha (opacity) values
	float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };

	public Triangle() {
		// initialize vertex byte buffer for shape coordinates
		ByteBuffer bb = ByteBuffer.allocateDirect(
		// (number of coordinate values * 4 bytes per float)
		triangleCoords.length * 4);
		// use the device hardware's native byte order
		bb.order(ByteOrder.nativeOrder());

		// create a floating point buffer from the ByteBuffer
		vertexBuffer = bb.asFloatBuffer();
		// add the coordinates to the FloatBuffer
		vertexBuffer.put(triangleCoords);
		// set the buffer to read the first coordinate
		vertexBuffer.position(0);

		// prepare shaders and OpenGL program
		int vertexShader = CameraRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
													 vertexShaderCode);
		int fragmentShader = CameraRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
													   fragmentShaderCode);

		mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
		GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
		GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
		GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables
	}

	public void draw(float[] mvpMatrix) {
		// Add program to OpenGL environment
		GLES20.glUseProgram(mProgram);

		// get handle to vertex shader's vPosition member
		m_positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

		// Enable a handle to the triangle vertices
		GLES20.glEnableVertexAttribArray(m_positionHandle);

		// Prepare the triangle coordinate data
		GLES20.glVertexAttribPointer(m_positionHandle, COORDS_PER_VERTEX,
									 GLES20.GL_FLOAT, false,
									 vertexStride, vertexBuffer);

		// get handle to fragment shader's vColor member
		m_colorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

		// Set color for drawing the triangle
		GLES20.glUniform4fv(m_colorHandle, 1, color, 0);

		// get handle to shape's transformation matrix
		m_mvpMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
		CameraRenderer.checkGlError("glGetUniformLocation");

		// Apply the projection and view transformation
		GLES20.glUniformMatrix4fv(m_mvpMatrixHandle, 1, false, mvpMatrix, 0);
		CameraRenderer.checkGlError("glUniformMatrix4fv");

		// Draw the triangle
		GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

		// Disable vertex array
		GLES20.glDisableVertexAttribArray(m_positionHandle);
	}
}

/*
 * Draw a square
 */
class Square {

	private final String vertexShaderCode =
			// This matrix member variable provides a hook to manipulate
			// the coordinates of the objects that use this vertex shader
			"uniform mat4 uMVPMatrix;" +

	        "attribute vec4 vPosition;" +
	        "void main() {" +
	        // the matrix must be included as a modifier of gl_Position
	        "  gl_Position = vPosition * uMVPMatrix;" +
	        "}";

	private final String fragmentShaderCode =
			"precision mediump float;" +
			"uniform vec4 vColor;" +
			"void main() {" +
			"  gl_FragColor = vColor;" +
			"}";

	private final FloatBuffer vertexBuffer;
	private final ShortBuffer drawListBuffer;
	private final int mProgram;
	private int mPositionHandle;
	private int mColorHandle;
	private int mMVPMatrixHandle;

	// number of coordinates per vertex in this array
	static final int COORDS_PER_VERTEX = 3;
	final float squareCoords[] = { -0.5f,  0.5f, 0.0f,   // top left
								   -0.5f, -0.5f, 0.0f,   // bottom left
								   	0.5f, -0.5f, 0.0f,   // bottom right
								   	0.5f,  0.5f, 0.0f }; // top right

	private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices

	private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

	// Set color with red, green, blue and alpha (opacity) values
	float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };

	public Square() {
		// initialize vertex byte buffer for shape coordinates
		ByteBuffer bb = ByteBuffer.allocateDirect(
		// (# of coordinate values * 4 bytes per float)
		squareCoords.length * 4);
		bb.order(ByteOrder.nativeOrder());
		vertexBuffer = bb.asFloatBuffer();
		vertexBuffer.put(squareCoords);
		vertexBuffer.position(0);

		// initialize byte buffer for the draw list
		ByteBuffer dlb = ByteBuffer.allocateDirect(
		// (# of coordinate values * 2 bytes per short)
		drawOrder.length * 2);
		dlb.order(ByteOrder.nativeOrder());
		drawListBuffer = dlb.asShortBuffer();
		drawListBuffer.put(drawOrder);
		drawListBuffer.position(0);

		// prepare shaders and OpenGL program
		int vertexShader = CameraRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
													 vertexShaderCode);
		int fragmentShader = CameraRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
													   fragmentShaderCode);

		mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
		GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
		GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
		GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables
	}

	public void draw(float[] mvpMatrix) {
		// Add program to OpenGL environment
		GLES20.glUseProgram(mProgram);

		// get handle to vertex shader's vPosition member
		mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

		// Enable a handle to the triangle vertices
		GLES20.glEnableVertexAttribArray(mPositionHandle);

		// Prepare the triangle coordinate data
		GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
									 GLES20.GL_FLOAT, false,
									 vertexStride, vertexBuffer);

		// get handle to fragment shader's vColor member
		mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

		// Set color for drawing the triangle
		GLES20.glUniform4fv(mColorHandle, 1, color, 0);

		// get handle to shape's transformation matrix
		mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
		CameraRenderer.checkGlError("glGetUniformLocation");

		// Apply the projection and view transformation
		GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
		CameraRenderer.checkGlError("glUniformMatrix4fv");

		// Draw the square
		GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
							  GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

		// Disable vertex array
		GLES20.glDisableVertexAttribArray(mPositionHandle);
	}
}

/*
 * Draws a square with textured with the image frame from the
 * camera preview call back.
 */
class SquareCameraTextured {

	private final String vertexShaderCode =
			// This matrix member variable provides a hook to manipulate
			// the coordinates of the objects that use this vertex shader
			"uniform mat4 uMVPMatrix;" +
	        "attribute vec4 vPosition;" +
			"attribute vec2 vTexCoord;" +
			"varying vec2 myTexCoord;" +
	        "void main() {" +
	        // the matrix must be included as a modifier of gl_Position
	        "  myTexCoord = vTexCoord;" +
	        "  gl_Position = uMVPMatrix * vPosition;" +
	        "}";

	private final String fragmentShaderCode =
			"precision mediump float;" +
			"uniform vec4 vColor;" +
			"uniform sampler2D vTexture;" +
			"varying vec2 myTexCoord;" +
			"void main() {" +
			//"  gl_FragColor = vColor;" +
			"  gl_FragColor = texture2D(vTexture, myTexCoord);" +
			"}";

	private FloatBuffer vertexBuffer;
	private final FloatBuffer textureBuffer;
	private final ShortBuffer drawListBuffer;
	private final int m_textureId;
	private final int m_textureIdx;
	private final int m_program;
	private int m_positionHandle;
	private int m_textureUniformHandle;
	private int m_textureCoordinateHandle;
	private int m_colorHandle;
	private int m_mvpMatrixHandle;
	
	// number of coordinates per vertex in this array
	static final int COORDS_PER_VERTEX = 3;
	static final int COORDS_PER_TEXCOORD = 2;
	final float camCoords[] = { -0.5f,  0.5f, 0.0f,   // top left
								-0.5f, -0.5f, 0.0f,   // bottom left
								 0.5f, -0.5f, 0.0f,   // bottom right
								 0.5f,  0.5f, 0.0f }; // top right
	
	static float camTexCoords[];
	
	private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices

	private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
	private final int texStride = COORDS_PER_TEXCOORD * 4; // 4 bytes per vertex

	// Set color with red, green, blue and alpha (opacity) values
	float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };

	public SquareCameraTextured(int texId, int texIdx) {
		int cols = CameraParams.cameraSize.x;
		int rows = CameraParams.cameraSize.y;
		int texsz = CameraParams.textureSize;
		
		m_textureId = texId;
		m_textureIdx = texIdx;
		
		// initialize vertex byte buffer for shape coordinates
		vertexBuffer = ByteBufferHelper.makeFloatBuffer(camCoords);
		
		// initialize the texture coordinates byte buffer	
		camTexCoords = new float[] {
				// Camera preview
				0.0f, 0.0f,
				0.0f, (float)rows/texsz,
				(float)cols/texsz, (float)rows/texsz,
				(float)cols/texsz, 0.0f
		};
		textureBuffer = ByteBufferHelper.makeFloatBuffer(camTexCoords);

		// initialize byte buffer for the draw list
		ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);	// (# of coordinate values * 2 bytes per short)
		dlb.order(ByteOrder.nativeOrder());
		drawListBuffer = dlb.asShortBuffer();
		drawListBuffer.put(drawOrder);
		drawListBuffer.position(0);

		// prepare shaders and OpenGL program
		int vertexShader = CameraRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
													 vertexShaderCode);
		int fragmentShader = CameraRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
													   fragmentShaderCode);

		m_program = GLES20.glCreateProgram();             // create empty OpenGL Program
		GLES20.glAttachShader(m_program, vertexShader);   // add the vertex shader to program
		GLES20.glAttachShader(m_program, fragmentShader); // add the fragment shader to program
		GLES20.glLinkProgram(m_program);                  // create OpenGL program executables
	}

	/*
	 * Draws our object given the model view projection matrix
	 * Modified this to take in a rotation angle and scale x,y,z
	 * so each drawn object has it's own rotation/scale. I do miss
	 * my push/pop.
	 */
	public void draw(float[] mvpMatrix, float angle, float[] scale) {
		float[] myMvpMatrix = new float[16];
		
		// object model view projection
		Matrix.setIdentityM(myMvpMatrix, 0);
		
        // Translate the object in the world given position matrix
        Matrix.translateM(myMvpMatrix, 0, 0.0f, 0.0f, 0.0f);
        
		// scale
        Matrix.scaleM(myMvpMatrix, 0, scale[0], scale[1], scale[2]);
                
        //rotate
        Matrix.rotateM(myMvpMatrix, 0, angle, 0.0f, 0.0f, 1.0f);
                
        Matrix.multiplyMM(myMvpMatrix, 0, mvpMatrix, 0, myMvpMatrix, 0);
        
        // enable texturing
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0 );
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, m_textureId);
        		
		// Add program to OpenGL environment
		GLES20.glUseProgram(m_program);

		// get handle to vertex shader's vPosition member
		m_positionHandle = GLES20.glGetAttribLocation(m_program, "vPosition");

		// Enable a handle to the triangle vertices
		GLES20.glEnableVertexAttribArray(m_positionHandle);
		
		// Prepare the triangle coordinate data
		GLES20.glVertexAttribPointer(m_positionHandle, COORDS_PER_VERTEX,
									 GLES20.GL_FLOAT, false,
									 vertexStride, vertexBuffer);
		
		// get handle to vertex shader's vTexCoord member
		m_textureCoordinateHandle = GLES20.glGetAttribLocation(m_program, "vTexCoord");
		
		// enable handle to the texture coordinates
		GLES20.glEnableVertexAttribArray(m_textureCoordinateHandle);
		
		// prepare the texture coordinates
		GLES20.glVertexAttribPointer(m_textureCoordinateHandle, COORDS_PER_TEXCOORD,
				 					 GLES20.GL_FLOAT, false,
				 					 texStride, textureBuffer);
		
		// get handle to the texture id
		m_textureUniformHandle = GLES20.glGetUniformLocation(m_program, "vTexture");
		
		// set the texture uniform
		GLES20.glUniform1i(m_textureUniformHandle, m_textureIdx);
		//Log.i("texdatahandle",Integer.toString(m_textureDataHandle));

		// get handle to fragment shader's vColor member
		m_colorHandle = GLES20.glGetUniformLocation(m_program, "vColor");

		// Set color for drawing the triangle
		GLES20.glUniform4fv(m_colorHandle, 1, color, 0);

		// get handle to shape's transformation matrix
		m_mvpMatrixHandle = GLES20.glGetUniformLocation(m_program, "uMVPMatrix");
		CameraRenderer.checkGlError("glGetUniformLocation");

		// Apply the projection and view transformation
		GLES20.glUniformMatrix4fv(m_mvpMatrixHandle, 1, false, myMvpMatrix, 0);
		CameraRenderer.checkGlError("glUniformMatrix4fv");

		// Draw the square
		GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
							  GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

		// Disable vertex array
		GLES20.glDisableVertexAttribArray(m_positionHandle);
		
		// disable texture
		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
	}
}

/*
 * Draws a square with a given textureId
 */
class SquareTextured {

	private final String vertexShaderCode =
			// This matrix member variable provides a hook to manipulate
			// the coordinates of the objects that use this vertex shader
			"uniform mat4 uMVPMatrix;" +
	        "attribute vec4 vPosition;" +
			"attribute vec2 vTexCoord;" +
			"varying vec2 myTexCoord;" +
	        "void main() {" +
	        // the matrix must be included as a modifier of gl_Position
	        "  myTexCoord = vTexCoord;" +
	        "  gl_Position = uMVPMatrix * vPosition;" +
	        "}";

	private final String fragmentShaderCode =
			"precision mediump float;" +
			"uniform vec4 vColor;" +
			"uniform sampler2D vTexture;" +
			"varying vec2 myTexCoord;" +
			"void main() {" +
			//"  gl_FragColor = vColor;" +
			"  gl_FragColor = texture2D(vTexture, myTexCoord);" +
			"}";

	private FloatBuffer vertexBuffer;
	private final FloatBuffer textureBuffer;
	private final ShortBuffer drawListBuffer;
	private final int m_textureId;
	private final int m_program;
	private int m_positionHandle;
	private int m_textureUniformHandle;
	private int m_textureCoordinateHandle;
	private int m_colorHandle;
	private int m_mvpMatrixHandle;
	
	// number of coordinates per vertex in this array
	static final int COORDS_PER_VERTEX = 3;
	static final int COORDS_PER_TEXCOORD = 2;
	final float camCoords[] = { -0.5f,  0.5f, 0.0f,   // top left
								-0.5f, -0.5f, 0.0f,   // bottom left
								 0.5f, -0.5f, 0.0f,   // bottom right
								 0.5f,  0.5f, 0.0f }; // top right
	
	static float camTexCoords[];
	
	private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices

	private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
	private final int texStride = COORDS_PER_TEXCOORD * 4; // 4 bytes per vertex

	// Set color with red, green, blue and alpha (opacity) values
	float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };

	public SquareTextured(int texIdx) {
		m_textureId = texIdx;
		
		// initialize vertex byte buffer for shape coordinates
		vertexBuffer = ByteBufferHelper.makeFloatBuffer(camCoords);
		
		// initialize the texture coordinates byte buffer	
		camTexCoords = new float[] {
				// Camera preview
				0.0f, 0.0f,
				0.0f, 1.0f,
				1.0f, 1.0f,
				1.0f, 0.0f
		};
		textureBuffer = ByteBufferHelper.makeFloatBuffer(camTexCoords);

		// initialize byte buffer for the draw list
		ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);	// (# of coordinate values * 2 bytes per short)
		dlb.order(ByteOrder.nativeOrder());
		drawListBuffer = dlb.asShortBuffer();
		drawListBuffer.put(drawOrder);
		drawListBuffer.position(0);

		// prepare shaders and OpenGL program
		int vertexShader = CameraRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
													 vertexShaderCode);
		int fragmentShader = CameraRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
													   fragmentShaderCode);

		m_program = GLES20.glCreateProgram();             // create empty OpenGL Program
		GLES20.glAttachShader(m_program, vertexShader);   // add the vertex shader to program
		GLES20.glAttachShader(m_program, fragmentShader); // add the fragment shader to program
		GLES20.glLinkProgram(m_program);                  // create OpenGL program executables
	}

	/*
	 * Draws our object given the model view projection matrix
	 * Modified this to take in a rotation angle and scale x,y,z
	 * so each drawn object has it's own rotation/scale. I do miss
	 * my push/pop.
	 */
	public void draw(float[] mvpMatrix, float angle, float[] scale) {
		float[] myMvpMatrix = new float[16];
		
		// object model view projection
		Matrix.setIdentityM(myMvpMatrix, 0);
		
        // Translate the object in the world given position matrix
        //Matrix.translateM(myMvpMatrix, 0, pos[0], pos[1], pos[2]);
        
		// scale
        Matrix.scaleM(myMvpMatrix, 0, scale[0], scale[1], scale[2]);
                
        //rotate
        Matrix.rotateM(myMvpMatrix, 0, angle, 0.0f, 0.0f, 1.0f);
                
        Matrix.multiplyMM(myMvpMatrix, 0, mvpMatrix, 0, myMvpMatrix, 0);
        		
		// Add program to OpenGL environment
		GLES20.glUseProgram(m_program);

		// get handle to vertex shader's vPosition member
		m_positionHandle = GLES20.glGetAttribLocation(m_program, "vPosition");

		// Enable a handle to the triangle vertices
		GLES20.glEnableVertexAttribArray(m_positionHandle);
		
		// Prepare the triangle coordinate data
		GLES20.glVertexAttribPointer(m_positionHandle, COORDS_PER_VERTEX,
									 GLES20.GL_FLOAT, false,
									 vertexStride, vertexBuffer);
		
		// get handle to vertex shader's vTexCoord member
		m_textureCoordinateHandle = GLES20.glGetAttribLocation(m_program, "vTexCoord");
		
		// enable handle to the texture coordinates
		GLES20.glEnableVertexAttribArray(m_textureCoordinateHandle);
		
		// prepare the texture coordinates
		GLES20.glVertexAttribPointer(m_textureCoordinateHandle, COORDS_PER_TEXCOORD,
				 					 GLES20.GL_FLOAT, false,
				 					 texStride, textureBuffer);
		
		// get handle to the texture id
		m_textureUniformHandle = GLES20.glGetUniformLocation(m_program, "vTexture");
		
		// set the texture uniform
		GLES20.glUniform1i(m_textureUniformHandle, m_textureId);
		//Log.i("texdatahandle",Integer.toString(m_textureDataHandle));

		// get handle to fragment shader's vColor member
		m_colorHandle = GLES20.glGetUniformLocation(m_program, "vColor");

		// Set color for drawing the triangle
		GLES20.glUniform4fv(m_colorHandle, 1, color, 0);

		// get handle to shape's transformation matrix
		m_mvpMatrixHandle = GLES20.glGetUniformLocation(m_program, "uMVPMatrix");
		CameraRenderer.checkGlError("glGetUniformLocation");

		// Apply the projection and view transformation
		GLES20.glUniformMatrix4fv(m_mvpMatrixHandle, 1, false, myMvpMatrix, 0);
		CameraRenderer.checkGlError("glUniformMatrix4fv");

		// Draw the square
		GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
							  GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

		// Disable vertex array
		GLES20.glDisableVertexAttribArray(m_positionHandle);
	}
}

class Mesh {

	private String m_vertexShaderCode;
	private String m_fragmentShaderCode;

	private FloatBuffer vertexBuffer;
	private FloatBuffer textureBuffer;
	private ShortBuffer faceBuffer;
	private int m_faces;
	private int m_textureId;
	private int m_textureIdx;
	private final int m_program;
	private int m_positionHandle;
	private int m_textureUniformHandle;
	private int m_textureCoordinateHandle;
	private int m_colorHandle;
	private int m_mvpMatrixHandle;
	
	// flags to use texture mapping or color shading
	private boolean m_isTextureOn = false;
	
	// number of coordinates per vertex in this array
	static final int COORDS_PER_VERTEX = 3;
	static final int COORDS_PER_TEXCOORD = 2;

	private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
	private final int texStride = COORDS_PER_TEXCOORD * 4; // 4 bytes per vertex

	// Set color with red, green, blue and alpha (opacity) values
	float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };

	public Mesh(boolean textureMode) {
		m_isTextureOn = textureMode;
		
		// prepare shaders and OpenGL program
		generateShaders();
		int vertexShader = CameraRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
													 m_vertexShaderCode);
		int fragmentShader = CameraRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
													   m_fragmentShaderCode);

		m_program = GLES20.glCreateProgram();             // create empty OpenGL Program
		GLES20.glAttachShader(m_program, vertexShader);   // add the vertex shader to program
		GLES20.glAttachShader(m_program, fragmentShader); // add the fragment shader to program
		GLES20.glLinkProgram(m_program);                  // create OpenGL program executables
	}
	
	private void generateShaders()
	{
		
		m_vertexShaderCode =
			// This matrix member variable provides a hook to manipulate
			// the coordinates of the objects that use this vertex shader
			"uniform mat4 uMVPMatrix;" +
		    "attribute vec4 vPosition;";
		
		if(m_isTextureOn)
		{
			m_vertexShaderCode +=  
			"attribute vec2 vTexCoord;" +
			"varying vec2 myTexCoord;";
		}
			
		m_vertexShaderCode +=
		    "void main() {";
			// the matrix must be included as a modifier of gl_Position
		
		if(m_isTextureOn)
		{
			m_vertexShaderCode +=
			"  myTexCoord = vTexCoord;";
		}
		
		m_vertexShaderCode +=
		    "  gl_Position = uMVPMatrix * vPosition;" +
			"}";
		
		m_fragmentShaderCode =
			"precision mediump float;" +
			"uniform sampler2D vTexture;" +
			"uniform vec4 vColor;" +
			"varying vec2 myTexCoord;" +
			"void main() {";
		
		if(m_isTextureOn)
		{
			m_fragmentShaderCode += "  gl_FragColor = texture2D(vTexture, myTexCoord);";
		}
		else
		{
			m_fragmentShaderCode += "  gl_FragColor = vColor;";
		}
		
		m_fragmentShaderCode += "}";		
	}
	
	/*
	 * Sets the vertex buffer with the data from the incoming vertex list
	 */
	public void setVertices(float[] verts)
	{
		// initialize vertex byte buffer for shape coordinates
		vertexBuffer = ByteBufferHelper.makeFloatBuffer(verts);
	}

	/*
	 * Takes a list of faces and generates the draw list buffer
	 */
	public void setFaces(short[] faces)
	{
		// initialize byte buffer for the draw list
		ByteBuffer dlb = ByteBuffer.allocateDirect(faces.length * 2);	// (# of coordinate values * 2 bytes per short)
		dlb.order(ByteOrder.nativeOrder());
		faceBuffer = dlb.asShortBuffer();
		faceBuffer.put(faces);
		faceBuffer.position(0);
		m_faces = faces.length;
	}

	/*
	 * Sets the texture coordinates given a list of texcoords
	 */
	public void setTexCoords(float[] texcoords)
	{
		textureBuffer = ByteBufferHelper.makeFloatBuffer(texcoords);
	}

	/* 
	 * Set the texture id to texture map this object
	 */
	public void setTexureId(int textureId, int textureIdx)
	{
		m_textureId = textureId;
		m_textureIdx = textureIdx;
	}
	
	/*
	 * Draws our object given the model view projection matrix
	 * Modified this to take in a rotation angle and scale x,y,z
	 * so each drawn object has it's own rotation/scale. I do miss
	 * my push/pop.
	 */
	public void draw(float[] mvpMatrix, float[]pos, float angle, float[] scale) {
		float[] myMvpMatrix = new float[16];
		
		// clear depth so it render on top of frame
		GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT);
		
		// object model view projection
		Matrix.setIdentityM(myMvpMatrix, 0);
		
        // Translate the object in the world given position matrix
        //Matrix.translateM(myMvpMatrix, 0, pos[0], pos[1], pos[2]);
        
		// scale
        Matrix.scaleM(myMvpMatrix, 0, scale[0], scale[1], scale[2]);
                
        //rotate
        Matrix.rotateM(myMvpMatrix, 0, angle, 0.0f, 1.0f, 0.0f);
                
        Matrix.multiplyMM(myMvpMatrix, 0, mvpMatrix, 0, myMvpMatrix, 0);
                      		
		// Add program to OpenGL environment
		GLES20.glUseProgram(m_program);

		// set triangle vertices
		m_positionHandle = GLES20.glGetAttribLocation(m_program, "vPosition");
		GLES20.glEnableVertexAttribArray(m_positionHandle);
		GLES20.glVertexAttribPointer(m_positionHandle, COORDS_PER_VERTEX,
									 GLES20.GL_FLOAT, false,
									 vertexStride, vertexBuffer);
		
		// set texture coords
		if(m_isTextureOn)
		{
			// enable gl texture
	        GLES20.glActiveTexture(GLES20.GL_TEXTURE1 );
	        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, m_textureId);
	        
			m_textureCoordinateHandle = GLES20.glGetAttribLocation(m_program, "vTexCoord");
			GLES20.glEnableVertexAttribArray(m_textureCoordinateHandle);
			GLES20.glVertexAttribPointer(m_textureCoordinateHandle, COORDS_PER_TEXCOORD,
										 GLES20.GL_FLOAT, false,
										 texStride, textureBuffer);

			// set texture
			m_textureUniformHandle = GLES20.glGetUniformLocation(m_program, "vTexture");
			CameraRenderer.checkGlError("glGetUniformLocation");
			GLES20.glUniform1i(m_textureUniformHandle, m_textureIdx);
			CameraRenderer.checkGlError("glUniformMatrix1i");
		}
		else
		{
			// set color
			m_colorHandle = GLES20.glGetUniformLocation(m_program, "vColor");
			CameraRenderer.checkGlError("glGetUniformLocation");
			GLES20.glUniform4fv(m_colorHandle, 1, color, 0);
			CameraRenderer.checkGlError("glUniformMatrix4fv");
		}
		
		// set projection and view transforms
		m_mvpMatrixHandle = GLES20.glGetUniformLocation(m_program, "uMVPMatrix");
		CameraRenderer.checkGlError("glGetUniformLocation");
		GLES20.glUniformMatrix4fv(m_mvpMatrixHandle, 1, false, myMvpMatrix, 0);
		CameraRenderer.checkGlError("glUniformMatrix4fv");
		
		// set handle to the textureMode in shader
		//int textureModeHandle = GLES20.glGetUniformLocation(m_program, "textureMode");
		//CameraRenderer.checkGlError("glGetUniformLocation");
		//if(m_isTexCoordsSet && m_isTexIdxSet) GLES20.glUniform1i(textureModeHandle, 1);
		//else GLES20.glUniform1i(textureModeHandle, 0);
		//CameraRenderer.checkGlError("glUniformMatrix1i");

		// Draw the square
		GLES20.glDrawElements(GLES20.GL_TRIANGLES, m_faces,
							  GLES20.GL_UNSIGNED_SHORT, faceBuffer);

		// Disable vertex array
		GLES20.glDisableVertexAttribArray(m_positionHandle);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
	}
}

